package org.cfk.delaytasktutorial.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cfk.delaytasktutorial.entity.LazyJob;
import org.cfk.delaytasktutorial.enums.LazyJobLazyLevel;
import org.cfk.delaytasktutorial.mapper.LazyJobMapper;
import org.cfk.delaytasktutorial.service.LazyJobService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class LazyJobServiceImpl implements LazyJobService {

    private final LazyJobMapper lazyJobMapper;
    private final RedissonClient redissonClient;
    private final DelayQueueManager delayQueueManager;
    private static final String LOCK_KEY = "lazy_job_lock";
    private static final long FIVE_MINUTES_MILLIS = 5 * 60 * 1000;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(String worker, String content, LocalDateTime util, LazyJobLazyLevel level) {
        // 计算延迟时间
        long delayMillis = java.time.Duration.between(LocalDateTime.now(), util).toMillis();
        
        // 5分钟内的任务直接放入Redisson队列
        if (delayMillis <= FIVE_MINUTES_MILLIS) {
            delayQueueManager.addTask(worker, content, util);
            log.info("短延迟任务已加入Redisson队列, worker: {}, delay: {}ms", worker, delayMillis);
        } else {
            // 超过5分钟的任务保存到数据库
            LazyJob lazyJob = new LazyJob()
                    .setWorker(worker)
                    .setContent(content)
                    .setUtil(util)
                    .setLazyJobLazyLevel(level.getCode())
                    .setTakeState(0)
                    .setDeleted(false)
                    .setCreateTime(LocalDateTime.now());
            lazyJobMapper.insert(lazyJob);
            log.info("长延迟任务已保存到数据库, worker: {}, executeTime: {}", worker, util);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<LazyJob> poll() {
        RLock lock = redissonClient.getLock(LOCK_KEY);
        List<LazyJob> result = new ArrayList<>();
        try {
            // 尝试获取锁，最多等待5秒，10秒后自动释放
            if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
                try {
                    // 查询未被取走且到期的任务
                    LambdaQueryWrapper<LazyJob> wrapper = new LambdaQueryWrapper<LazyJob>()
                            .eq(LazyJob::getTakeState, 0)
                            .eq(LazyJob::getDeleted, false)
                            .le(LazyJob::getUtil, LocalDateTime.now().plus(5, ChronoUnit.MINUTES))
                            .last("limit 1000");

                    List<LazyJob> jobs = lazyJobMapper.selectList(wrapper);
                    for (LazyJob job : jobs) {
                        // 尝试标记任务为已取走状态
                        if (lazyJobMapper.takeJob(job.getId()) > 0) {
                            result.add(job);
                        }
                    }
                } finally {
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            log.error("获取延迟任务锁失败", e);
            Thread.currentThread().interrupt();
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        lazyJobMapper.deleteById(id);
    }
}